﻿/*******************************************************
 * 
 * 作者：胡庆访
 * 创建时间：20100326
 * 说明：DockableContent到Region适配器
 * 运行环境：.NET 3.5 SP1
 * 版本号：1.0.0
 * 
 * 历史记录：
 * 创建文件 胡庆访 20100326
 * 
*******************************************************/
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using Avalon.Windows.Controls;
using AvalonDock;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Regions;
using Microsoft.Practices.Composite.Presentation.Regions.Behaviors;
using Microsoft.Practices.Composite.Regions;
using OpenExpressApp.Event;
using OpenExpressApp.Template;

namespace OpenExpressApp.Host.WPF
{
    /// <summary> 
    /// DockableContent到Region适配器
    /// 
    /// 用于修复Dock控件在收缩之后，断掉与Shell的逻辑树关系，导致不能找到RegionManager及Region的问题。
    /// </summary>
    internal class DockableContentRegionAdapter : ContentControlRegionAdapter
    {
        public DockableContentRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
            : base(regionBehaviorFactory) { }

        /// <summary>
        /// 除了代码内指定部分，本方法其余代码与基类的代码一模一样。
        /// </summary>
        /// <param name="region"></param>
        /// <param name="regionTarget"></param>
        protected override void AttachDefaultBehaviors(IRegion region, ContentControl regionTarget)
        {
            IRegionBehaviorFactory behaviorFactory = this.RegionBehaviorFactory;
            if (behaviorFactory != null)
            {
                DependencyObject dependencyObjectRegionTarget = regionTarget as DependencyObject;
                foreach (string behaviorKey in behaviorFactory)
                {
                    if (!region.Behaviors.ContainsKey(behaviorKey))
                    {
                        IRegionBehavior behavior = behaviorFactory.CreateFromKey(behaviorKey);
                        if (dependencyObjectRegionTarget != null)
                        {
                            IHostAwareRegionBehavior hostAwareRegionBehavior = behavior as IHostAwareRegionBehavior;
                            if (hostAwareRegionBehavior != null)
                            {
                                hostAwareRegionBehavior.HostControl = dependencyObjectRegionTarget;
                            }
                        }

                        //添加这一行代码用于修改
                        this.EnhanceAccessor(regionTarget, behavior);

                        region.Behaviors.Add(behaviorKey, behavior);
                    }
                }
            }
        }

        /// <summary>
        /// 加强behavior 的 RegionManagerAccessor
        /// </summary>
        /// <param name="regionTarget"></param>
        /// <param name="behavior"></param>
        private void EnhanceAccessor(ContentControl regionTarget, IRegionBehavior behavior)
        {
            var registration = behavior as RegionManagerRegistrationBehavior;
            if (registration != null)
            {
                if ((behavior is ShellRegionManagerAccessor) == false)
                {
                    //直接使用Shell来找RegionManger
                    registration.RegionManagerAccessor = new ShellRegionManagerAccessor(regionTarget);
                }
            }
        }

        /// <summary>
        /// 使用Shell来找RegionManger的GetRegionManager方法实现方式
        /// </summary>
        private class ShellRegionManagerAccessor : IRegionManagerAccessor
        {
            /// <summary>
            /// 根元素，也就是附加了RegionManager的窗体对象。
            /// </summary>
            private DependencyObject _shell;

            public ShellRegionManagerAccessor(DependencyObject element)
            {
                this.FindShell(element);
            }

            /// <summary>
            /// 使用shell来获取RegionManager
            /// </summary>
            /// <param name="element"></param>
            /// <returns></returns>
            public IRegionManager GetRegionManager(DependencyObject element)
            {
                return this._shell.GetValue(RegionManager.RegionManagerProperty) as IRegionManager;
            }

            #region 这两个方法代码同MS的原代码

            public event EventHandler UpdatingRegions
            {
                add
                {
                    RegionManager.UpdatingRegions += value;
                }
                remove
                {
                    RegionManager.UpdatingRegions -= value;
                }
            }

            public string GetRegionName(DependencyObject element)
            {
                return (element.GetValue(RegionManager.RegionNameProperty) as string);
            }

            #endregion

            /// <summary>
            /// 找到element的根元素
            /// </summary>
            /// <param name="element"></param>
            private void FindShell(DependencyObject element)
            {
                if (element == null) throw new ArgumentNullException("element");

                //找到根元素
                DependencyObject parent = element;
                DependencyObject rootParent = null;
                while (parent != null)
                {
                    rootParent = parent;
                    parent = LogicalTreeHelper.GetParent(parent);
                }

                this._shell = rootParent;
            }
        }
    }
}
